/**
 * Created by felix on 2017/2/16.
 */
import _ from 'lodash';
import { delay } from '../utils/';

const respondHandler = ({
    xs = 480,
    sm = 960,
    md = 1440,
}, cur) => {
    let size;
    if (cur <= xs) {
        size = 'xs';
    } else if (cur <= sm) {
        size = 'sm';
    } else if (cur <= md) {
        size = 'md';
    } else {
        size = 'lg';
    }
    return size;
};

const scrollHandler = (target, wrap, put) => {
    const distance = target.scrollTop;
    const targetH = parseInt(target.offsetHeight, 10);
    const wrapH = parseInt(wrap.offsetHeight, 10);
    const scrollBottom = wrapH - targetH;

    put({
        type: 'onScroll',
        payload: {
            distance,
            scrollBottom,
        }
    });
};
let timeout = 0;
const listen = (target, wrap) => (dispatch) => {
    const d = document.getElementById(wrap);
    delay(10).then(() => {
        if (!d) {
            if (timeout < 5000) {
                timeout += 10;
                listen(target, wrap)(dispatch);
            } else {
                console.error(wrap, '加载超时，或不存在');
            }
        } else {
            const t = document.getElementById(target);
            t.onscroll = () => {
                scrollHandler(t, d, dispatch);
            };
        }
    });
};
const makeAction = ({ reducer, keys, value, name, state }) => {
    if (typeof state !== 'object' || (keys && keys.length < 1)) {
        return;
    }
    for (const k of keys) {
        state[k] = value;
    }
    return {
        type: reducer,
        payload: {
            [name]: state
        }
    };
};
const visibleAction = ({ keys, value, state }) => makeAction({
    reducer: 'visible',
    name: 'visible',
    keys,
    value,
    state,
});
const parseCss = (value) => {
    let result = new Array(4);
    if (value instanceof Array) {
        const len = value.length;
        switch (len) {
            case 1:
                return _.map(result, () => value[0]);
            case 2:
                return _.map(result, (r, i) => {
                    if (i % 2 === 0) {
                        return value[0];
                    } else {
                        return value[1];
                    }
                });
            case 3:
                return _.map(result, (r, i) => {
                    if (i === 0) {
                        return value[0];
                    } else if (i === 3) {
                        return value[2];
                    } else {
                        return value[1];
                    }
                });
            case 4:
                return _.map(result, (r, i) => {
                    return value[i];
                });
            default: {
                const r = new Array(4);
                return _.map(r, () => value);
            }
        }
    } else {
        const r = new Array(4);
        return _.map(r, () => value);
    }
};
const getKeys = (args) => {
    const result = [];
    for (let k in args) {
        if (!args[k]) {
            result.push(k);
        }
    }
    return result;
};

export default {
    namespace: 'flex',
    state: {
        visible: {
            header: true,
            footer: true,
            left: true,
            right: true,
        },
        size: null,
        scroll: {
            distance: 0,
            up: false,
            down: false,
            scroll: false,
            top: false,
            bottom: false,
        },
        config: {
            isPin: [false, false, false, false], //遵循css方向缩略定义规则
            header: '64px',
            footer: '32px',
            left: '240px',
            right: '220px',
            during: '.5s',
            xs: 480,
            sm: 960,
            md: 1440,
        },
    },
    reducers: {
        scroll(state, { payload }) {
            return {
                ...state,
                scroll: payload,
            };
        },
        resize(state, { payload }) {
            const { size } = payload;
            return {
                ...state,
                size,
            };
        },
        visible(state, { payload }) {
            const { visible } = payload;
            return {
                ...state,
                visible,
            };
        },
        setting(state, { payload }) {
            const { config: newConfig } = payload;
            const { config: oldConfig } = state;
            return {
                ...state,
                config: {
                    ...oldConfig,
                    ...newConfig
                },
            };
        },
    },
    effects: {
        *toggleSideBar({ payload }, { put, select }) {
            const { visible: old } = yield select((state) => state.flex);
            const visible = {
                ...old,
                ...payload,
            };
            yield put({
                type: 'visible',
                payload: {
                    visible,
                }
            });
        },
        *flexSet({ payload }, { put, select }) {
            const { size: oldSize, config, visible: v } = yield select((state) => state.flex);
            const { isPin } = config;
            const { wiw } = payload;
            const size = respondHandler(config, wiw);
            if (size && size !== oldSize) {
                yield put({
                    type: 'resize',
                    payload: {
                        size,
                    },
                });
                const [, right, , left] = parseCss(isPin);
                const keys = getKeys({
                    right,
                    left,
                });
                if (keys.length > 0) {
                    if ((size === 'sm' || size === 'xs')) {
                        yield put(visibleAction({
                            keys,
                            value: false,
                            state: v,
                        }));
                    } else {
                        yield put(visibleAction({
                            keys,
                            value: true,
                            state: v,
                        }));
                    }
                }
            }
        },
        onStopScroll: [function* onStopScroll({ payload }, { put }) {
            /* 触发结束滚动 */
            yield put({
                type: 'scroll',
                payload,
            });
        }, {
            type: 'takeLatest',
        }],
        onScroll: [function* onScroll({ payload }, { put, select }) {
            const flex = yield select((state) => state.flex);
            const { distance: justNow } = flex.scroll;
            const { distance, scrollBottom } = payload;
            const { config: { isPin }, visible: v } = flex;

            const [header, , footer] = parseCss(isPin);
            const keys = getKeys({
                header,
                footer,
            });
            if (distance === 0) {
                yield put({
                    type: 'scroll',
                    payload: {
                        up: false,
                        down: false,
                        scroll: false,
                        top: true,
                        bottom: false,
                        distance,
                    },
                });
            } else if (distance >= scrollBottom) {
                yield put({
                    type: 'scroll',
                    payload: {
                        up: false,
                        down: false,
                        scroll: false,
                        top: false,
                        bottom: true,
                        distance,
                    },
                });
            } else if (distance > justNow) {
                /* 向下滚动 */
                yield put({
                    type: 'scroll',
                    payload: {
                        up: false,
                        down: true,
                        scroll: true,
                        top: false,
                        bottom: false,
                        distance,
                    },
                });
                if (keys.length > 0 && (v.header || v.footer)) {
                    yield put(visibleAction({
                        keys,
                        value: false,
                        state: v,
                    }));
                }
            } else {
                yield put({
                    type: 'scroll',
                    payload: {
                        up: true,
                        down: false,
                        scroll: true,
                        top: false,
                        bottom: false,
                        distance,
                    },
                });
                if (keys.length > 0 && (!v.header || !v.footer)) {
                    yield put(visibleAction({
                        keys,
                        value: true,
                        state: v,
                    }));
                }
            }
            yield put({
                type: 'onStopScroll',
                payload: {
                    up: false,
                    down: false,
                    scroll: false,
                    top: false,
                    bottom: false,
                    distance,
                }
            });
        }, {
            type: 'takeLatest',
        }],
        *resetVertical({ payload }, { put, select }) {
            const { visible: v } = yield select((state) => state.flex);
            if (!v.header || !v.footer) {
                yield put(visibleAction({
                    keys: ['header', 'footer'],
                    value: true,
                    state: v,
                }));
            }
        },
    },
    subscriptions: {
        listenResize({ dispatch }) {
            const resize = () => {
                const wiw = window.innerWidth;
                dispatch({
                    type: 'flexSet',
                    payload: {
                        wiw,
                    }
                });
            };
            window.onresize = () => {
                resize();
            };
            window.onload = () => {
                resize();
            };
        },
        listenScroll({ dispatch }) {
            listen('_content', '_contWrap')(dispatch);
        },
        routeChange({ dispatch, history }) {
            history.listen(() => {
                delay(0).then(() => {
                    listen('_content', '_contWrap')(dispatch);
                    dispatch({
                        type: 'resetVertical'
                    });
                });
            });
        }
    },
};
